文件格式 File Formats
常见的存储数据的文件格式:
CSV
纯文本文件,包含一行行数据(逗号分隔)。
A plain text file contains rows of data (comma separated values)。
例子:
1 | Sherlock Holmes,221B Baker Street,Detective |
- 简单、可读性好
- 非常流行、应用广
- 但细节很多
- 分隔符可自定义(如用 Tab 的 TSV)
- 字段里若含有分隔符需要加引用(引号)
- 如果字符串内部再包含引号,需要转义:
"string with "" inside"
- 适合:扁平表格数据(行列结构),与 Excel/数据库导入导出;不适合复杂嵌套。
XML
一种用于编码(半)结构化数据的文本格式。
A text format encoding (semi-)structured data。
例子
1 | <characters> |
- 格式本身比 CSV 标准化得更好
- 也适合表示嵌套数据
- 人类可读,但不太好手写
- 很冗长,完整 XML 规范也很复杂
- 支持高级特性(如 XML Schema),但不常用
- 有一定流行度,但在走下坡路
JSON
源自 JavaScript 对象表示法的文本格式。
A text format stemming from JavaScript Object Notation。
例子
1 | [ |
- 用途与 XML 类似
- 但格式更简单
- 更不啰嗦(verbose)、更易书写
- 正在变得越来越流行
命令行工具 Command Line Tools
Text files are quite popular because they are human readable and easy to use.
这部分主要讲如何利用命令行工具处理txt文件。
组合工具(Combining Tools)
每个程序都有一个输入流(input stream)以及输出流(output stream)。可以将多个命令组合起来:
把两个命令连接起来(Concatenating both):
1
command 1 | command 2
把输出重定向到文件(Redirecting to a file):
1
command > file
从文件重定向为输入(Redirecting from a file):
1
command < file
错误流(error stram):
1
command 2 > /dev/null
- Unix 流编号:
0
—标准输入 stdin,1
—标准输出 stdout,2
—标准错误 stderr。 - 把
command
的错误流重定向到空设备/dev/null
(像“黑洞”一样,会丢弃输入)。
- Unix 流编号:
读取文件(Reading Files): cat
读取单个文件:
1
cat file
连接多个文件:
1
cat file1 file2 file3
接受管道输入:
1
command | cat
转义/可视化二进制数据:
1
cat -v binaryfile
处理压缩文件:
1
zcat / bzcat / xzcat
主要用作其他命令的输入
分页查看结果(Paging reults):less
用于检查结果或文件,分页显示,可向前向后滚动。
在管道中通常用作最后一个命令。
分页命令输出:
1
command | less
分页查看文件:
1
less file
截断长行:
1
less -S
过滤(Filtering):grep
返回所有匹配行——功能强大、选项众多。
过滤输入:
1
cat file1 file2 | grep 'img[0-9]*\.jpg'
过滤文件:
1
grep 'img[0-9]*\.jpg' *.html
只返回匹配片段:
1
command | grep -o 'user=.*$'
返回不匹配的行:
1
grep -v '^warning' logfile
不区分大小写:
1
cat file | grep -i '\.jpg' file
排序(Sorting):sort
按某种准则对输入排序:
基本排序:
1
cat file | sort
数字排序:
1
cat file | sort -n
按特定键排序:
1
cat file | sort -k 2
以第 2 列开始直到行尾作为排序键进行排序(默认字典序,升序,按空白分隔列;多个空格/Tab 会被合并为一个分隔符,前导空白被忽略)。
指定分隔符排序:
1
cat file | sort -t ',' -k 3
把逗号当作列分隔符,用从第3列到行尾的内容按字典序排序。
排序并去重:
1
cat file | sort -u
非常强大且有用
- 能处理大于内存的文件
- 已排序的文件可作为其他算法的输入
选前/后缀(Selecting Prefix/Sufix):head
/ tail
返回文件开头/结尾:
前 20 条:
1
head -20 file
1
sort file | head -20
这两条命令的结果是不一样的
后 15 条:
1
sort file | tail -15
除前两条外的全部:
1
sort file | tail -n +3
除最后两条外的全部:
1
sort file | head -n -2
这些都是top-k查询——先排序再
head
/tail
。也可用于最小/最大值计算。
处理重复(Handling Duplicates):uniq
处理已排序输入中的重复:
去重:
1
sort file | uniq
计数重复:
1
sort file | uniq -c
仅返回重复行:
1
sort file | uniq -d
仅返回唯一行:
1
sort file | uniq -u
对分组与计数很有用
投影列(Projection Columns):cut
语法:
1
cut OPTION... [FILE]...
只返回输入中相关部分:
返回特定字段:
1
cat file | cut -f 1,3
指定分隔符切分:
1
cat file | cut -f 2-4 -d ','
按字符位置切分:
1
cat file | cut -c 1-10
计数(Counting):wc
统计行/词/字符数量:
全量统计:
1
cat file | wc
只数行数:
1
cat file | wc -l
只数字节数:
1
cat file | wc -c
有助于收集数据统计。
乱序(Shuffling):shuf
将输入的行打乱生成随机排列:
随机顺序:
1
cat file | shuf
不太常用,但在某些场景很有用:
随机抽样:
1
cat file | shuf | head -10000
适合性能测试。
编辑文本(Editing Text):sed
语法:
1
sed 's/regex/repl/flags'
s
是 substitute(替换)的意思。- 第 1 个分隔符后是正则(要匹配的内容),第 2 个分隔符后是替换文本,最后是标志位(可选)。
- 默认每行只替换第 1 处匹配;加
g
才是“本行全替”。 &
在替换文本里表示“整段匹配的内容”;\1
、\2
… 表示捕获组。sed
的默认正则是 BRE(Basic Regular Expressions):分组要写\(
\)
;如果用-E
(或 GNU-r
),就变成 ERE 分组可用(
)
。
用一个文本替换另一个文本:
基本替换:
1
2
3cat file | sed 's/oldText/newText/'
sed 's/oldText/newText/' file对每一行,把第一次出现的
oldText
替换成newText
。只影响每行第一个匹配,后面的同一行匹配保持不变。替换所有出现:
1
cat file | sed 's/oldText/newText/g'
反向引用:
1
cat file | sed 's/IMG_\([0-9]*\).JPG/image\1.jpg/g'
把诸如
IMG_123.JPG
转为image123.jpg
。IMG_
:字面匹配。\([0-9]*\)
:捕获组(因为是 BRE 要写\(
\)
)。匹配零个或多个数字;匹配到的数字被记为组 1。- 替换串
image\1.jpg
:把组 1(即数字)插回去。 g
:该行所有匹配都替换。
不区分大小写匹配:
1
cat file | sed 's/file[0-9]*.png/"&"/I'
使用多个规则:
1
cat file | sed -e 's/old1/new1/' -e 's:a/b:a_b:'
极其强大且有用;
还有分组、条件分支等更多特性,但很少用。
合并文件(Combining Files):join
合并已排序输入文件:
按公共字段合并两个文件:
1
join -1 2 -2 1 file1 file2
用
file1
的第2列与file2
的第1列作为“键”做内连接-1 2
:指定 file1 的键列是第 2 列。-2 1
:指定 file2 的键列是第 1 列。- 没有指定分隔符 ⇒ 用空白切列;多个空白算一个分隔;前导空白被忽略。
- 没有
-a/-v
⇒ 内连接(仅输出两边都出现的键)。
指定分隔符合并:
1
join -1 2 -2 1 -d ',' file1 file2
保留未匹配行(
-a
):1
join -1 2 -2 1 -a 1 file1 file2
行为类似关系型连接;但如果需要更强功能,可能应使用更强大的工具。
选项说明:
-1 FIELD
:file1 以该字段连接;-2 FIELD
:file2 以该字段连接-a 1
左外连接;-a 2
右外连接;-a 1 -a 2
全外连接-v
抑制已连接的输出行:-v 1
左反连接;-v 2
右反连接
计算(Computation):awk
为输入的每一行执行程序:
通用结构:
1
awk 'BEGIN{init}{per-line}END{done}' file
计数行数:
1
awk 'BEGIN{x=0}{x=x+1}END{print x}'
累加某列:
1
awk 'BEGIN{x=0}{x=x+$2}END{print x}'
求某列平均:
1
awk 'BEGIN{x=0;y=0}{x+=\$2;y+=1}END{print x/y}'
条件:
1
awk 'BEGIN{x=0}{if ($1>10) x+=\$2}END{print x}'